package cn.bonoon.kernel.web.handlers.loader;

import java.util.ArrayList;
import java.util.Date;

import cn.bonoon.kernel.descriptors.EntityDescriptor;
import cn.bonoon.kernel.descriptors.EntityPropertyAccessor;
import cn.bonoon.kernel.events.ReadEvent;
import cn.bonoon.kernel.support.entities.Persistable;
import cn.bonoon.kernel.support.searcher.Finder;
import cn.bonoon.kernel.util.StringHelper;

/**
 * 可以使用java自身的字节码(反射)处理来优化
 * @author jackson
 *
 */
public class QueryParser extends ArrayList<SimpleQuery>{
	/**
	 * 
	 */
	private static final long serialVersionUID = 2336449368267715413L;
	
	public void parse(Finder finder, ReadEvent event){
		for (SimpleQuery sq : this) {
			String value = event.getString(sq.source);
			if(null != value){
				finder.and(sq.and, sq.to(value));
			}
		}
	}
	
	public void addQuery(EntityDescriptor entityDescriptor, String query){
		String name, opt = null;
		if(query.startsWith("qe_")){
			name = query.substring(3);
			opt = "=";
		}else if(query.startsWith("li_")){
			name = query.substring(3);
			opt = " like ";
		}else if(query.startsWith("lt_")){
			name = query.substring(3);
			opt = "<";
		}else if(query.startsWith("le_")){
			name = query.substring(3);
			opt = "<=";
		}else if(query.startsWith("gt_")){
			name = query.substring(3);
			opt = ">";
		}else if(query.startsWith("ge_")){
			name = query.substring(3);
			opt = ">=";
		}else if(query.startsWith("ll_")){
			name = query.substring(3);
			opt = "ll";
		}else if(query.startsWith("rl_")){
			name = query.substring(3);
			opt = "rl";
		}else if(query.startsWith("ne_")){
			name = query.substring(3);
			opt = "<>";
		}else{
			name = query;
		}
		EntityPropertyAccessor epa = entityDescriptor.get(name);
		if(null == epa) return;
		Class<?> type = epa.getType();
		if(type == String.class){
			String s = "", e = "";
			if(null == opt){//默认情况下，字符串使用like，其它情况直接使用=号
				opt = " like ";
				s = "%";
				e = "%";
			}else if("ll".equals(opt)){
				opt = " like ";
				s = "%";
			}else if("rl".equals(opt)){
				opt = " like ";
				e = "%";
			}
			this.add(new StringQuery(query, name, opt, s, e));
			return;
		}
		
		if(null == opt){
			opt = "=";
		}
		
		if(Persistable.class.isAssignableFrom(type)){
			SimpleQuery lsq = new LongQuery(query, name + ".id", opt);
			this.add(lsq);
			return;
		}
		SimpleQuery sq = IntQuery.findQuery(type, query, name, opt);
		if(null != sq){
			this.add(sq);
		}
	}
}
/**
 * 8. byte -> null
 * @author jackson
 *
 */
class ByteQuery extends SimpleQuery{
	static SimpleQuery findQuery(Class<?> type, String source, String name, String opt){
		if(type == byte.class || type == Byte.class) return new ByteQuery(source, name, opt);
		return null;
	}
	ByteQuery(String source, String name, String opt) {
		super(source, name, opt);
	}

	@Override
	Object to(String value) {
		return Byte.valueOf(value);
	}
	
}
/**
 * 7. short -> byte
 * @author jackson
 *
 */
class ShortQuery extends SimpleQuery{
	static SimpleQuery findQuery(Class<?> type, String source, String name, String opt){
		if(type == short.class || type == Short.class) return new ShortQuery(source, name, opt);
		return ByteQuery.findQuery(type, source, name, opt);
	}
	ShortQuery(String source, String name, String opt) {
		super(source, name, opt);
	}

	@Override
	Object to(String value) {
		return Short.valueOf(value);
	}
	
}
/**
 * 6. char -> short
 * @author jackson
 *
 */
class CharacterQuery extends SimpleQuery{
	static SimpleQuery findQuery(Class<?> type, String source, String name, String opt){
		if(type == char.class || type == Character.class) return new CharacterQuery(source, name, opt);
		return ShortQuery.findQuery(type, source, name, opt);
	}
	CharacterQuery(String source, String name, String opt) {
		super(source, name, opt);
	}

	@Override
	Object to(String value) {
		return Character.valueOf(value.charAt(0));
	}
}
/**
 * 5. flaot -> char
 * @author jackson
 *
 */
class FloatQuery extends SimpleQuery{
	static SimpleQuery findQuery(Class<?> type, String source, String name, String opt){
		if(type == float.class || type == Float.class) return new FloatQuery(source, name, opt);
		return CharacterQuery.findQuery(type, source, name, opt);
	}
	FloatQuery(String source, String name, String opt) {
		super(source, name, opt);
	}

	@Override
	Object to(String value) {
		return Float.valueOf(value);
	}
	
}
/**
 * 4. boolean -> float
 * @author jackson
 *
 */
class BooleanQuery extends SimpleQuery{
	static SimpleQuery findQuery(Class<?> type, String source, String name, String opt){
		if(type == boolean.class || type == Boolean.class) return new BooleanQuery(source, name, opt);
		return FloatQuery.findQuery(type, source, name, opt);
	}
	BooleanQuery(String source, String name, String opt) {
		super(source, name, opt);
	}

	@Override
	Object to(String value) {
		return Boolean.valueOf(value);
	}
	
}
/**
 * 3. double -> boolean
 * @author jackson
 *
 */
class DoubleQuery extends SimpleQuery{
	static SimpleQuery findQuery(Class<?> type, String source, String name, String opt){
		if(type == double.class || type == Double.class) return new DoubleQuery(source, name, opt);
		return BooleanQuery.findQuery(type, source, name, opt);
	}
	DoubleQuery(String source, String name, String opt) {
		super(source, name, opt);
	}

	@Override
	Object to(String value) {
		return Double.valueOf(value);
	}
	
}
/**
 * 2. long -> double
 * @author jackson
 *
 */
class LongQuery extends SimpleQuery{
	static SimpleQuery findQuery(Class<?> type, String source, String name, String opt){
		if(type == long.class || type == Long.class) return new LongQuery(source, name, opt);
		return DoubleQuery.findQuery(type, source, name, opt);
	}
	LongQuery(String source, String name, String opt) {
		super(source, name, opt);
	}

	@Override
	Object to(String value) {
		return Long.valueOf(value);
	}
	
}
/**
 * date -> long
 * @author jackson
 *
 */
class DateQuery extends SimpleQuery{
	static SimpleQuery findQuery(Class<?> type, String source, String name, String opt){
		if(type.equals(Date.class)) return new DateQuery(source, name, opt);
		return LongQuery.findQuery(type, source, name, opt);
	}
	DateQuery(String source, String name, String opt) {
		super(source, name, opt);
	}

	@Override
	Object to(String value) {
		return StringHelper.toDate(value);
	}
	
}
/**
 * 1. int -> date
 * @author jackson
 *
 */
class IntQuery extends SimpleQuery{
	static SimpleQuery findQuery(Class<?> type, String source, String name, String opt){
		if(type == int.class || type == Integer.class) return new IntQuery(source, name, opt);
		return DateQuery.findQuery(type, source, name, opt);
	}
	IntQuery(String source, String name, String opt) {
		super(source, name, opt);
	}

	@Override
	Object to(String value) {
		return Integer.valueOf(value);
	}
	
}
class StringQuery extends SimpleQuery{
	private final String s, e;
	StringQuery(String source, String name, String opt, String s, String e) {
		super(source, name, opt);
		this.s = s;
		this.e = e;
	}

	@Override
	Object to(String value) {
		return s + value + e;
	}
	
}
abstract class SimpleQuery{
	SimpleQuery(String source, String name, String opt){
		this.source = source;
		this.name = name;
		this.and = "x." + name + opt + "?";
	}
	final String source, name, and;
	
	abstract Object to(String value);
}